﻿#region MortgageCalcModel
//
// All rights are reserved. Reproduction or transmission in whole or in part, in 
// any form or by any means, electronic, mechanical or otherwise, is prohibited 
// without the prior written consent of the copyright owner.
// 
// Filename: MortgageCalcModel.cs
//
#endregion using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.ComponentModel;
using System;

namespace DiscoveryLogic.DataServices.DataSources
{
    public class MortgageCalcModel : INotifyPropertyChanged
    {
        private bool _inCalculation = false;
        private double _savingsAmount = 0;
        private double _previousNextPaymentAmount;
        private DateTime _previousProjectedPaymentCompleteDate;

        private readonly MortgageAccount _account;
        private readonly DateTime _initialCompletionDate;
        private readonly double _maxPayment = 5000; // max of the cylinder. 
        private readonly DateTime _minDate = new DateTime(2012, 7, 1); // to make the graph slider work

        public MortgageCalcModel(MortgageAccount account)
        {
            _account = account;
            _initialCompletionDate = _account.ProjectedPaymentCompleteDate;
            StorePrevious();

            _account.PropertyChanged += new PropertyChangedEventHandler(Account_PropertyChanged);

            CalculateSavings();
        }

        public MortgageAccount Account
        {
            get { return _account; }
        }

        private void StorePrevious()
        {
            _previousNextPaymentAmount = _account.NextPaymentAmount;
            _previousProjectedPaymentCompleteDate = _account.ProjectedPaymentCompleteDate;
        }

        public void SuspendCalculation()
        {
            _inCalculation = true;
        }
        public void ResumeCalculation()
        {
            _inCalculation = false;
        }

        private void Account_PropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            //A guard since setting the properties will fire the DetailChanged event again.
            if (_inCalculation) return;

            try
            {
                _inCalculation = true;
                if (e.PropertyName == "NextPaymentAmount")
                {
                    _previousProjectedPaymentCompleteDate = _account.ProjectedPaymentCompleteDate;
                    CalculateProjectedPaymentCompleteDate();
                }
                else if (e.PropertyName == "ProjectedPaymentCompleteDate")
                {
                    _previousNextPaymentAmount = _account.NextPaymentAmount;
                    CalulateNextPaymentAmount();
                }

                CalculateSavings();
            }
            finally
            {
                _inCalculation = false;
            }
        }

        private void CalculateProjectedPaymentCompleteDate()
        {
            double delta = _account.NextPaymentAmount - _previousNextPaymentAmount;
            _previousNextPaymentAmount = _account.NextPaymentAmount;


            DateTime newDate = _account.ProjectedPaymentCompleteDate.AddDays(-(delta * 2));
            if (newDate > _account.PaymentSchedule.EndDate)
                newDate = _account.PaymentSchedule.EndDate;
            if (newDate < _minDate)
                newDate = _minDate;

            _account.ProjectedPaymentCompleteDate = newDate;
        }

        private void CalulateNextPaymentAmount()
        {
            TimeSpan delta = _account.ProjectedPaymentCompleteDate - _previousProjectedPaymentCompleteDate;
            _previousProjectedPaymentCompleteDate = _account.ProjectedPaymentCompleteDate;

            //Just randomly choose a scaling factor based on the number of days gone by
            double newPayment = _account.NextPaymentAmount - (delta.TotalDays / 2);
            newPayment = Math.Max(_account.MinimumPayment, newPayment);
            newPayment = Math.Min(MaxPayment, newPayment);

            _account.NextPaymentAmount = newPayment;
        }

        public void CalculateSavings()
        {
            DateTime completeDate = _account.ProjectedPaymentCompleteDate;

            // Money saved on interest
            double savings = 0;

            if (completeDate < _initialCompletionDate)
            {
                TimeSpan interval = (_initialCompletionDate - completeDate);
                savings = Math.Round((interval.Days / 365.0) * 12.0 * _account.NextPaymentInterest / 2);
            }

            SavingsAmount = savings;
        }

        public double MaxPayment
        {
            get { return _maxPayment; }
        }

        public double SavingsAmount
        {
            get { return _savingsAmount; }
            set
            {
                if (_savingsAmount != value)
                {
                    _savingsAmount = value;

                    OnPropertyChanged(new PropertyChangedEventArgs("SavingsAmount"));
                }
            }
        }

        #region INotifyPropertyChanged Members

        public event PropertyChangedEventHandler PropertyChanged = delegate { };

        protected virtual void OnPropertyChanged(PropertyChangedEventArgs args)
        {
            PropertyChanged(this, args);
        }

        #endregion
    }
}
